var Consts = require('../../../util/consts');
var RoomRemote = require('../remote/roomRemote');
var messageService = require('../../../services/messageService');

module.exports = function (app) {
    return new EntryHandler(app);
};

var EntryHandler = function (app) {
    this.app = app;
    this.roomRemote = new RoomRemote(app);
};

var handler = EntryHandler.prototype;

var allHides = {};


var admin = 'backgroundAdmin';

/**
 * 东西已经放好
 * @param msg
 * @param session
 * @param next
 */
handler.endHide = function (msg, session, next) {
    var self = this;
    var rid = session.get('rid');
    /**
     * msg: {urls:[], username:xxx, rid:xxx}
     */
    var urls = msg.urls;
    var username = msg.username;

    if (urls == null || urls.length === 0) {
        next(null, {code: Consts.code.FAIL, msg: 'hide one thing at least'});
        return;
    }
    var hides = [];
    for (var i = 0; i < urls.length; i++) {
        hides[i] = {
            master: username,
            url: urls[i],
            status: Consts.hideStatus.NOT_FOUND,
            findBy: []
        };
    }
    if (allHides[rid] == null) {
        allHides[rid] = [];
    }
    allHides[rid] = allHides[rid].concat(hides);

    var channelService = this.app.get('channelService');
    var channel = channelService.getChannel(rid, false);
    if (channel) {
        // exist
        var members = channel.getMembers();
        // exclude master from seek queue
        for (var idx = 0; idx < members.length; idx++) {
            if (members[idx].split('*')[0] == username) {
                members.splice(idx, 1);
                break;
            }
        }
        var i = members.length;
        var j = hides.length;
        while (i-- > 0) {
            var member = members[i];
            j--;
            if (j < 0) {
                j += hides.length;
            }
            if (hides[j].findBy.indexOf(member) === -1) {
                hides[j].findBy.push(member);
            }
            var target = member.split('*')[0];
            var myMsg = {
                rid: rid,
                content: JSON.stringify({url: hides[j].url, action: Consts.HAS_ACTION.START_SEEK}),
                from: username,
                target: target
            };
            self._sendMessage(admin, rid, myMsg, null);
        }

        // update score board
        var scoreMsg = {};
        scoreMsg.action = Consts.HAS_ACTION.UPDATE_SCOREBOARD;

        scoreMsg.scoreBoard = this._newestScoreBoard(hides, this._getRoomMembers(rid), username);
        scoreMsg.msg = "update score board";
        self._broadcastMessage(scoreMsg, username, rid, null);
        next(null, {code: Consts.code.SUCCESS});

    } else {
        // not exist
        next(null, {code: Consts.code.FAIL});
    }


};


handler._sendMessage = function (username, rid, msg, next) {

    messageService.send(username, msg.target, msg.content, rid, Consts.GameRoute.HIDE_AND_SEEK_GAME, this.app);

    if (next !== null) {
        next(null, {
            route: msg.route
        });
    }
};

/**
 * @param msg {username: xxx, url: xxx}
 * @param session
 * @param next
 */
handler.found = function (msg, session, next) {
    var rid = session.get('rid');
    var hides = allHides[rid];
    var url = msg.url;
    var username = msg.username;
    var i;
    var self = this;
    for (i = 0; i < hides.length; i++) {
        var hide = hides[i];
        if (hide.url === url) {
            var myMsg = {};
            if (hide.status === Consts.hideStatus.NOT_FOUND) {
                hide.status = Consts.hideStatus.FOUND;
                hide.findBy = [username];
            }

            myMsg.currentUrl = url;
            var j = 0;
            for (; j < hides.length; j++) {
                if (i === j) {
                    continue;
                }
                // get new hide to found
                if (hides[j].status === Consts.hideStatus.NOT_FOUND) {
                    var newHide = hides[j];
                    newHide.findBy = newHide.findBy.concat(hide['findBy']);
                    myMsg.nextUrl = newHide.url;
                    myMsg.findBy= username;
                    myMsg.action = Consts.HAS_ACTION.FIND_NEXT;

                    var masterMsg = myMsg, seekerMsg = myMsg;
                    // 发送给找到的人的消息
                    masterMsg.msg = 'Good Work!!!';
                    // 发送给其他人的消息
                    seekerMsg.msg = 'Found by other people... Come on!!!';
                    self._broadcastMessageOnCondition(masterMsg, seekerMsg, username, rid, null);

                    break;
                }
            }

            // update score board
            var scoreMsg = {};
            scoreMsg.action = Consts.HAS_ACTION.UPDATE_SCOREBOARD;
            var self = this;
            this.roomRemote.getRoom(rid, function (err, room) {
                scoreMsg.scoreBoard = self._newestScoreBoard(hides, self._getRoomMembers(rid), room['master']);
                scoreMsg.msg = "update score board";
                self._broadcastMessage(scoreMsg, username, rid, null);
                if ( j === hides.length) {
                    var myMsg = {};
                    myMsg.action = Consts.HAS_ACTION.END_GAME;
                    myMsg.msg = "All hides have been found. Game Over.";
                    self._broadcastMessage(myMsg, username, rid, null);
                }
                next(null, {
                    code: "success"
                });
            });


            if (j === hides.length) {

                break;
            }
        }
    }

    next(null, {
        code: "success"
    });
};

handler._broadcastMessageOnCondition = function (masterMsg, seekerMsg, mastername, rid, next) {
    var channelService = this.app.get('channelService');
    var channel = channelService.getChannel(rid, false);
    if (channel) {
        var members = channel.getMembers();
        for (var k = 0; k < members.length; k++) {
            var member = members[k];

            var target = member.split('*')[0];
            var myMsg = {};
            if (target === mastername) {
                myMsg = masterMsg;
            } else {
                myMsg = seekerMsg;
            }
            this._sendMessage(admin, rid, {
                rid: rid,
                content: JSON.stringify(myMsg),
                from: mastername,
                target: target
            }, next);
        }
    }
};
handler._getRoomMembers = function (rid) {
    var roomMembers = [];
    var channelService = this.app.get('channelService');
    var channel = channelService.getChannel(rid, false);
    if (channel) {
        var members = channel.getMembers();
        for (var k = 0; k < members.length; k++) {
            var member = members[k];

            var target = member.split('*')[0];
            roomMembers.push(target);
        }
    }
    return roomMembers;
};

handler._broadcastMessage = function (myMsg, username, rid, next) {
    this._sendMessage(admin, rid, {
        rid: rid,
        content: JSON.stringify(myMsg),
        from: username,
        target: '*'
    }, null);
};
var base_score = 10;
handler._newestScoreBoard = function (currentHides, usernames, mastername) {
    var scoreBoard = {};
    for (var i = 0; i < usernames.length; i++) {
        var username = usernames[i];
        var role = Consts.role.SEEKER;
        if (username === mastername)
            role = Consts.role.HIDER;
        scoreBoard[username] = {
            username: username,
            score: 0,
            role: role
        };
    }
    if (!currentHides) {
        return [];
    }
    // 已经找到的数量
    var foundCount = 0;
    // 藏的总数量
    var hideCount = currentHides.length;
    for (var i = 0; i < hideCount; i++) {
        var currentHide = currentHides[i];
        if (currentHide.status == Consts.hideStatus.FOUND) {
            foundCount++;
            if (scoreBoard[currentHide.findBy[0]]) {
                scoreBoard[currentHide.findBy[0]]['score'] += base_score;
            }
        }
    }
    if (scoreBoard[mastername]) {
        scoreBoard[mastername]['score'] = base_score * (hideCount - foundCount);
    } else {
        // something goes wrong
        console.log('update score board without master');
    }
    return scoreBoard;
};

